package com.hst.capacity.application.biz.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.smartravel.traffic.usoft17.RideSupplierCallback;
import cn.smartravel.traffic.usoft17.model.request.callback.OrderStatusDTO;
import cn.smartravel.traffic.usoft17.model.response.callback.ResultVO;
import com.alibaba.fastjson2.JSON;
import com.hst.capacity.application.biz.ExpressOrderBiz;
import com.hst.capacity.application.biz.JobPlatformBiz;
import com.hst.capacity.domain.common.constants.Constants;
import com.hst.capacity.domain.common.constants.MessageTemplate;
import com.hst.capacity.domain.common.constants.TongChengConstants;
import com.hst.capacity.domain.exception.BusinessException;
import com.hst.capacity.domain.model.entity.account.ExDriverAccountDetailEntity;
import com.hst.capacity.domain.model.entity.driver.DriverEntity;
import com.hst.capacity.domain.model.entity.driver.DriverProfileEntity;
import com.hst.capacity.domain.model.entity.member.MemberEntity;
import com.hst.capacity.domain.model.entity.order.express.*;
import com.hst.capacity.domain.model.entity.order.intercity.IntercityOrderEntity;
import com.hst.capacity.domain.model.entity.order.job.JobPlatformEntity;
import com.hst.capacity.domain.model.entity.setting.price.ExpressCommonPriceEntity;
import com.hst.capacity.domain.model.entity.setting.price.ExpressStpPriceEntity;
import com.hst.capacity.domain.model.entity.setting.station.ApplyStationEntity;
import com.hst.capacity.domain.model.entity.vehicle.VehicleEntity;
import com.hst.capacity.domain.model.request.OrderParam;
import com.hst.capacity.domain.model.request.dispatch.DispatchDriverParam;
import com.hst.capacity.domain.model.request.dispatch.DispatchParam;
import com.hst.capacity.domain.model.request.dispatcher.DispatcherSearchOrderParam;
import com.hst.capacity.domain.model.request.express.*;
import com.hst.capacity.domain.model.request.price.*;
import com.hst.capacity.domain.model.response.PagingResultVO;
import com.hst.capacity.domain.model.response.driver.DriverInfoVO;
import com.hst.capacity.domain.model.response.express.*;
import com.hst.capacity.domain.model.response.order.ExOrderInfoVO;
import com.hst.capacity.domain.model.response.order.OrderPriceVO;
import com.hst.capacity.domain.model.response.order.OrderVO;
import com.hst.capacity.domain.model.response.setting.RouteVO;
import com.hst.capacity.domain.repository.redis.CacheRedis;
import com.hst.capacity.domain.repository.redis.RouteRedis;
import com.hst.capacity.domain.service.*;
import com.hst.capacity.infra.convertor.ExpressConvertor;
import com.hst.capacity.infra.convertor.OrderConvertor;
import com.hst.capacity.infra.persistence.jpa.account.ExDriverAccountDetailRepository;
import com.hst.capacity.infra.persistence.jpa.driver.DriverProfileRepository;
import com.hst.capacity.infra.persistence.jpa.driver.DriverRepository;
import com.hst.capacity.infra.persistence.jpa.order.express.*;
import com.hst.capacity.infra.persistence.jpa.order.job.JobPlatformRepository;
import com.hst.capacity.infra.persistence.jpa.setting.price.ExCommonPriceRepository;
import com.hst.capacity.infra.persistence.jpa.setting.price.ExStpPriceRepository;
import com.hst.capacity.infra.persistence.jpa.setting.station.ApplyStationRepository;
import com.hst.capacity.infra.persistence.jpa.vehicle.VehicleRepository;
import com.hst.capacity.infra.persistence.jpa.vehicle.VehicleTypeRepository;
import com.hst.capacity.infra.persistence.mybatis.ExpressOrderMapper;
import com.hst.capacity.infra.util.DateUtil;
import com.hst.capacity.infra.util.NumUtil;
import com.hst.capacity.infra.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

@Slf4j
@Service
public class ExpressOrderBizImpl implements ExpressOrderBiz {

    @Autowired
    ExOrderRepository orderRepository;

    @Autowired
    ExOrderHistoryRepository orderHistoryRepository;

    @Autowired
    ExOrderSettlementRepository orderSettlementRepository;

    @Autowired
    ExDriverAccountDetailRepository accountDetailRepository;

    @Autowired
    ExOrderOperationHistoryRepository exOrderOperationHistoryRepository;

    @Autowired
    ExCommonPriceRepository expressCommonPriceRepository;

    @Autowired
    ExStpPriceRepository exStpPriceRepository;

    @Autowired
    ExpressService expressService;

    @Autowired
    ExOrderDispatchRepository exDispatchRepository;

    @Autowired
    MemberService memberService;

    @Autowired
    ExpressOrderMapper orderMapper;

    @Autowired
    DriverRepository driverRepository;

    @Autowired
    ExOrderDestroyRepository destroyRepository;

    @Autowired
    DriverProfileRepository driverProfileRepository;

    @Autowired
    DriverService driverService;

    @Autowired
    VehicleService vehicleService;

    @Autowired
    JobPlatformRepository jobRepository;

    @Autowired
    VehicleTypeRepository vehicleTypeRepository;

    @Autowired
    ExOrderSettlementRepository exOrderSettlementRepository;

    @Autowired
    ExOrderStatusHistoryRepository orderStatusHistoryRepository;

    @Autowired
    ExOrderCancelHistoryRepository orderCancelHistoryRepository;

    @Autowired
    VehicleRepository vehicleRepository;

    @Autowired
    JobPlatformBiz jobPlatformBiz;

    @Autowired
    ApplyStationRepository applyStationRepository;

    @Autowired
    ExOrderResultRepository exOrderResultRepository;

    @Autowired
    RideSupplierCallback callback;

    @Autowired
    RouteRedis routeRedis;

    @Autowired
    AuthService authService;

    @Autowired
    CacheRedis cacheRedis;

    @Override
    public OrderVO refresh(OrderParam param) {
        ExpressOrderEntity order = orderRepository.findByIdOrder(param.getIdOrder());
        return OrderConvertor.INSTANCE.exOrderToView(order);
    }

    /**
     * 获取用户的所有快车订单
     * @param param
     * @return
     */
    @Override
    public PagingResultVO<ExpressOrderEntity> findExOrderListByUserMobile(ExListUserParam param) {
        Pageable pageable = PageRequest.of(param.getPageIndex()-1, param.getPageSize(), Sort.Direction.DESC, "createTime");
        Page<ExpressOrderEntity> page = orderRepository.findByUserMobile(param.getUserMobile(), pageable);
        return new PagingResultVO<>(page.getTotalElements(),page.getContent());
    }

    /**
     * 获取区域下所有的快车订单
     * @param param
     * @return
     */
    @Override
    public PagingResultVO<ExpressOrderEntity> findExOrderListByRegionCode(ExListRegionParam param) {
        Pageable pageable = PageRequest.of(param.getPageIndex()-1,param.getPageSize(), Sort.Direction.DESC, "createTime");
        Page<ExpressOrderEntity> page = orderRepository.findByRegionCode(param.getRegionCode(), pageable);
        return new PagingResultVO<>(page.getTotalElements(),page.getContent());
    }

    /**
     * 获取今日创建的快车订单
     * @param param
     * @return
     */
    @Override
    public PagingResultVO<ExListNewVO> getNewExOrderList(ExListNewParam param) {
//        ExListParam convert = Convert.convert(ExListParam.class, param);
//        convert.setCreatTimeF(DateTimeUtil.getStartTimeOfDay());
//        convert.setCreatTimeE(DateTimeUtil.getEndTimeOfDay());
//        return ExpressConvertor.INSTANCE.convertNew(expressService.searchWithConditionsAndPaging(convert));
//        param.setCreatTimeF(DateUtil.getStartTimeOfDay());
//        param.setCreatTimeE(DateUtil.getEndTimeOfDay());
//        param.setAppointmentTime(DateUtil.getStartTimeOfDay());
        param.setAppointmentTimeF(DateUtil.getYestodayLocalDate());;
        if (param.getHourRange()==null){
            param.setHourRange(Constants.OrderFastSearchType.ALl);
        }
        switch (param.getHourRange()) {
            case Constants.OrderFastSearchType.ALl:
                break;
//            case Constants.OrderModuleType.EXPRESS:
//                break;
            default:
                LocalDateTime appointmentTimeE = DateUtil.getXHoursLaterDateTime(param.getHourRange());
                param.setAppointmentTimeE(cn.hutool.core.date.DateUtil.format(appointmentTimeE,Constants.DATE_FORMAT));
                param.setAppointmentTimeF(DateUtil.getNowLocalDate());;
                break;
        }
        return new PagingResultVO<>(orderMapper.getNewExOrderListTotal(param), orderMapper.getNewExOrderList(param));
    }

    /**
     * 获取今日创建的快车订单
     * @param param
     * @return
     */
    @Override
    public PagingResultVO<ExListNewVO> getNewExOrderListByRegionCode(ExListNewParam param) {
        ExListParam convert = Convert.convert(ExListParam.class, param);
        convert.setCreatTimeF(DateUtil.getStartTimeOfDay());
        convert.setCreatTimeE(DateUtil.getEndTimeOfDay());
        convert.setRegionCodes(param.getRegionCodes());
        return ExpressConvertor.INSTANCE.convertNew(expressService.searchWithConditionsAndPaging(convert));
    }

    /**
     * 获取站点以及快车价格
     * @param param
     * @return
     */
    @Override
    public OrderPriceVO getExpressStpPrice(ExpressPriceParam param) {

        RouteVO routeVO = routeRedis.calOrderDistance(
                param.getCoordinateType()
                , param.getOrigins(), param.getDestinations());

        if (routeVO == null)
            return null;

        param.setOrderDistance(routeVO.getDistance());
        param.setSpendTime(routeVO.getSpendTime());

        ApplyStationEntity entity = applyStationRepository.findByIdStation(param.getIdStation());
        if (entity == null)
            throw new BusinessException(5002, "站点业务未开通，请核查是否开通业务");

        log.info("ApplyStationEntity :" + JSON.toJSONString(entity));
        log.info("ExpressPriceParam :" + JSON.toJSONString(param));

        boolean stp = false;
        if (param.getInStation() == 0) {
            stp = (entity.getPickStationType() == 0);
        } else {
            stp = (entity.getSendStationType() == 0);
        }

        OrderPriceVO orderPrice = null;
        if (stp) {
            log.info("stp 计算价格");
            orderPrice = stpMoneyCalculate(param);
        } else {
            log.info("快车 计算价格");
            orderPrice = moneyCalculate(param);
        }

        return orderPrice;
    }

    /**
     * 获取城乡出行的价格
     * @param param
     * @return
     */
    @Override
    public OrderPriceVO getContrysidePrice(ContrySidePriceParam param) {

        RouteVO routeVO = routeRedis.calOrderDistance(
                param.getCoordinateType()
                , param.getOrigins(), param.getDestinations());

        if (routeVO == null)
            return null;

//        RouteMatrixVO rm = routeMatrix.getDriving(param.getOrigins(), param.getDestinations());
//        if (rm.getStatus()!=0){
//            throw new BusinessException(5000,"百度地图调用失败,"+rm.getMessage());
//        }
        OrderPriceVO orderPrice = null;
        param.setOrderDistance(routeVO.getDistance());
        param.setSpendTime(routeVO.getSpendTime());
        orderPrice = csMoneyCalculate(param);
        return orderPrice;
    }

    @Override
    public ExpressOrderEntity saveExpressStpOrder(ExpressCreateOrderParam param) {

        //1，乘客账户存在时，前端未传值的情况下，取得乘客信息放到对应参数当中
        MemberEntity member = memberService.createNewMember(param.getUserMobile());

        //定价ID未知时，取得并保存
        ExpressPriceParam stpParam = new ExpressPriceParam();
        stpParam.setRegionCode(param.getRegionCode());
        stpParam.setInStation(param.getInStation());
        StringBuilder origins = new StringBuilder(param.getStartAddressLatitude()).append(",").append(param.getStartAddressLongitude());
        StringBuilder destinations = new StringBuilder(param.getEndAddressLatitude()).append(",").append(param.getEndAddressLongitude());
        stpParam.setOrigins(origins.toString());
        stpParam.setDestinations(destinations.toString());
        stpParam.setCarpoolType(param.getCarpoolType());
        stpParam.setIdStation(param.getIdStation());

        OrderPriceVO oprv = this.getExpressStpPrice(stpParam);

        //创建订单
        ExpressOrderEntity entity = null;
        boolean isCreate = true;
        if (StringUtil.isBlank(param.getIdOrder())) {
            entity = new ExpressOrderEntity();
            entity.setIdOrder(StringUtil.createOrderID(9));
            entity.setCreateBy("capacity");
        } else {
            entity = orderRepository.findById(param.getIdOrder()).get();
            if (entity == null)
                throw new BusinessException(5002, "订单不存在，请检查参数idOrder是否正确");
            isCreate = false;
            entity.setIdOrder(param.getIdOrder());
            entity.setUpdateBy("capacity");
        }
        entity.setIdMember(member.getIdMember());
        entity.setIdFranchisee(param.getIdFranchisee());
        entity.setIdServicePriceType(oprv.getIdServicePriceType());
        entity.setIdServiceType(param.getIdServiceType());
        entity.setIdVehicleType(param.getIdVehicleType());
        entity.setIdTask(param.getIdTask());
        entity.setRegionCode(param.getRegionCode());
        entity.setPriceRule(param.getPriceRule());
        entity.setOrderType(Constants.ExpressServiceType.STP_EXPRESS);
        entity.setCarpoolType(param.getCarpoolType());//拼车包车用这个
        entity.setCarpoolService(param.getCarpoolService());
        entity.setIdStation(param.getIdStation());
        entity.setInStation(param.getInStation());
        entity.setUserName(param.getUserName());
        entity.setUserMobile(param.getUserMobile());
        entity.setPassengerName(param.getUserName());//传值下单用户名
        entity.setPassengerMobile(param.getPassengerMobile());
        entity.setPassengerNumber(param.getPassengerNumber());
        entity.setAppointmentTime(DateUtil.parseLocalDateTime(param.getAppointmentTime()));
        if (StringUtil.isBlank(param.getCutOffTime()))
            entity.setCutOffTime(DateUtil.parseLocalDateTime(param.getAppointmentTime()));
        else
            entity.setCutOffTime(DateUtil.parseLocalDateTime(param.getCutOffTime()));
        entity.setAssignTime(DateUtil.parseLocalDateTime(param.getAssignTime()));
        entity.setDriverLongitude(param.getDriverLongitude());
        entity.setDeptime(DateUtil.parseLocalDateTime(param.getDeptime()));
        entity.setStartAddress(param.getStartAddress());
        entity.setStartAddressLongitude(param.getStartAddressLongitude());
        entity.setStartAddressLatitude(param.getStartAddressLatitude());
        entity.setEndAddress(param.getEndAddress());
        entity.setEndAddressLongitude(param.getEndAddressLongitude());
        entity.setEndAddressLatitude(param.getEndAddressLatitude());
        entity.setDesttime(DateUtil.parseLocalDateTime(param.getDesttime()));
        entity.setDropOffArea(param.getDropOffArea());
        entity.setDropOffAreaLongitude(param.getDropOffAreaLongitude());
        entity.setDropOffAreaLatitude(param.getDropOffAreaLatitude());
        entity.setOrderSource(param.getOrderSource());
        int status = Constants.OrderStatus.ORDER_STATUS_CREATED;
        if (param.getStatus() != null)
            status = param.getStatus();
        entity.setStatus(status);
        int paymentStatus = (param.getPaymentStatus() == null) ? Constants.PaymentStatus.UN_PAY : param.getPaymentStatus();
        entity.setPaymentStatus(paymentStatus);
        int paymentRequitment = (param.getPaymentRequitment() == null) ? Constants.PaymentRequitment.IN_ADVANCE : param.getPaymentRequitment();
        entity.setPaymentRequitment(paymentRequitment);
        entity.setDivideAccountsStatus(Constants.DivideAccountsStatus.UN);
        entity.setReferenceDistance(oprv.getOrderDistance());
        entity.setEstimatedTime(oprv.getSpendTime());
        float money = oprv.getTotalPrice();
        if (param.getCarpoolType() == 0)
            money = money * param.getPassengerNumber();
        entity.setEstimatedMoney(money);
        entity.setOrderMemo(param.getOrderMemo());
        entity = (ExpressOrderEntity) orderRepository.save(entity);

        if (isCreate) {
            //追加订单状态
            ExpressOrderStatusHistoryEntity orderStatus = new ExpressOrderStatusHistoryEntity();
            orderStatus.setIdOrder(entity.getIdOrder());
            orderStatus.setStatus(entity.getStatus());
            orderStatus.setCreateBy("capacity");
            orderStatus.setMemo("运力商系统录入订单");
            orderStatusHistoryRepository.save(orderStatus);
        } else {
            //修改记录

        }

        //订单结果(未完成)
        ExpressOrderResultEntity resultEntity = exOrderResultRepository.findByIdOrder(entity.getIdOrder());
        if (resultEntity == null)
            resultEntity = OrderConvertor.INSTANCE.exOrderReslutConvert(param);

        resultEntity.setIdOrder(entity.getIdOrder());
        resultEntity.setOrderDistance(oprv.getOrderDistance());
        resultEntity.setOrderReferenceDistance(oprv.getOrderDistance());
        resultEntity.setOrderSpendTime(oprv.getSpendTime());
        resultEntity.setIdServicePriceSetting(oprv.getIdServicePriceType());
        resultEntity.setOrderBasePrice(oprv.getBasePrice());
        resultEntity.setOrderPerKilometres(oprv.getPerKilometres());
        resultEntity.setOrderPerTime(oprv.getPerTime());
        resultEntity.setOverMileMoney(oprv.getOverMileMoney());
        resultEntity.setOverTimeMoney(oprv.getOverTimeMoney());
        resultEntity.setBaseTotalMoney(oprv.getTotalPrice());
        exOrderResultRepository.save(resultEntity);

        return entity;
    }

    /**
     * 创建快车以及站点订单
     * @param param
     * @return
     */
    @Override
    public ExpressOrderEntity createExpressOrder(ExpressCreateOrderParam param) {

        //1，乘客账户存在时，前端未传值的情况下，取得乘客信息放到对应参数当中
        MemberEntity member = memberService.createNewMember(param.getUserMobile());

        OrderPriceVO oprv = null;

        //定价ID未知时，取得并保存
        ExpressPriceParam exPriceParam = new ExpressPriceParam();
        exPriceParam.setRegionCode(param.getRegionCode());
        exPriceParam.setInStation(param.getInStation());
        StringBuilder origins = new StringBuilder(param.getStartAddressLatitude()).append(",").append(param.getStartAddressLongitude());
        StringBuilder destinations = new StringBuilder(param.getEndAddressLatitude()).append(",").append(param.getEndAddressLongitude());
        exPriceParam.setOrigins(origins.toString());
        exPriceParam.setDestinations(destinations.toString());
        exPriceParam.setCarpoolType(param.getCarpoolType());
        if (StringUtil.isNotBlank(param.getIdFranchisee()))
            exPriceParam.setIdFranchisee(param.getIdFranchisee());

        //OrderPriceVO vo = new OrderPriceVO();
        if (Constants.ExSubBizType.InnerCity == param.getSubBizType()) {
            oprv = this.getExpressPrice(exPriceParam);
        }
        if (Constants.ExSubBizType.StationToStation == param.getSubBizType()) {
            exPriceParam.setIdStation(param.getIdStation());
            oprv = this.getExpressStpPrice(exPriceParam);
        }

        //创建订单
        ExpressOrderEntity order = new ExpressOrderEntity();
        if (StringUtil.empty2Null(param.getIdOrder())==null) {
            order.setIdOrder(StringUtil.createOrderID(9, param.getIdServiceType()));
            order.setIdTask(param.getIdTask());
            order.setIdFranchisee(param.getIdFranchisee());
            order.setRegionCode(param.getRegionCode());
            order.setOrderType(Constants.ExpressServiceType.STP_EXPRESS);
            order.setStatus(Constants.OrderStatus.ORDER_STATUS_CREATED);
            int paymentStatus = (param.getPaymentStatus() == null) ? Constants.PaymentStatus.UN_PAY : param.getPaymentStatus();
            order.setPaymentStatus(paymentStatus);
            int paymentRequitment = (param.getPaymentRequitment() == null) ? Constants.PaymentRequitment.IN_ADVANCE : param.getPaymentRequitment();
            order.setPaymentRequitment(paymentRequitment);
            order.setDivideAccountsStatus(Constants.DivideAccountsStatus.UN);
            order.setCreateBy("capacity");
        } else {
            order = orderRepository.findByIdOrder(param.getIdOrder());
            //entity.setIdOrder(param.getIdOrder());
            order.setUpdateBy("capacity");
        }
        order.setIdMember(member.getIdMember());

        order.setIdServicePriceType(oprv.getIdServicePriceType());
        order.setIdServiceType(param.getIdServiceType());
        order.setIdVehicleType(param.getIdVehicleType());

        // Todo 订单子类型
        //order.setCarpoolType(param.getSubBizType());
        order.setPriceRule(param.getPriceRule());

        order.setCarpoolType(param.getCarpoolType());//拼车包车用这个
        order.setCarpoolService(param.getCarpoolService());//拼车包车用这个
        order.setIdStation(param.getIdStation());
        order.setInStation(param.getInStation());
        order.setUserName(param.getUserName());
        order.setUserMobile(param.getUserMobile());
        order.setPassengerName(param.getUserName());//传值下单用户名
        order.setPassengerMobile(param.getPassengerMobile());
        order.setPassengerNumber(param.getPassengerNumber());
        order.setAppointmentTime(DateUtil.parseLocalDateTime(param.getAppointmentTime()));
        order.setAssignTime(DateUtil.parseLocalDateTime(param.getAssignTime()));
        order.setDriverLongitude(param.getDriverLongitude());
        order.setDeptime(DateUtil.parseLocalDateTime(param.getDeptime()));
        order.setStartAddress(param.getStartAddress());
        order.setStartAddressLongitude(param.getStartAddressLongitude());
        order.setStartAddressLatitude(param.getStartAddressLatitude());
        order.setEndAddress(param.getEndAddress());
        order.setEndAddressLongitude(param.getEndAddressLongitude());
        order.setEndAddressLatitude(param.getEndAddressLatitude());
        order.setDesttime(DateUtil.parseLocalDateTime(param.getDesttime()));
        order.setDropOffArea(param.getDropOffArea());
        order.setDropOffAreaLongitude(param.getDropOffAreaLongitude());
        order.setDropOffAreaLatitude(param.getDropOffAreaLatitude());
        order.setOrderSource(param.getOrderSource());

        order.setReferenceDistance(oprv.getOrderDistance());
        order.setEstimatedTime(oprv.getSpendTime());
        float money = oprv.getTotalPrice();
        if (param.getCarpoolType() == 0)
            money = money * param.getPassengerNumber();
        order.setEstimatedMoney(money);
        order.setOrderMemo(param.getOrderMemo());

        order.setSubBizType(param.getSubBizType());

        order = (ExpressOrderEntity) orderRepository.save(order);

        //追加订单状态
        ExpressOrderStatusHistoryEntity orderStatus = new ExpressOrderStatusHistoryEntity();
        orderStatus.setIdOrder(order.getIdOrder());
        orderStatus.setStatus(order.getStatus());
        orderStatus.setCreateBy("capacity");
        orderStatus.setMemo("运力商系统录入订单");
        orderStatusHistoryRepository.save(orderStatus);

        //订单结果(未完成)
        ExpressOrderResultEntity resultEntity = exOrderResultRepository.findByIdOrder(order.getIdOrder());
        if (resultEntity == null)
            resultEntity = OrderConvertor.INSTANCE.exOrderReslutConvert(param);

        resultEntity.setIdOrder(order.getIdOrder());
        resultEntity.setOrderDistance(oprv.getOrderDistance());
        resultEntity.setOrderReferenceDistance(oprv.getOrderDistance());
        resultEntity.setOrderSpendTime(oprv.getSpendTime());
        resultEntity.setIdServicePriceSetting(oprv.getIdServicePriceType());
        resultEntity.setOrderBasePrice(oprv.getBasePrice());
        resultEntity.setOrderPerKilometres(oprv.getPerKilometres());
        resultEntity.setOrderPerTime(oprv.getPerTime());
        resultEntity.setOverMileMoney(oprv.getOverMileMoney());
        resultEntity.setOverTimeMoney(oprv.getOverTimeMoney());
        resultEntity.setBaseTotalMoney(oprv.getTotalPrice());
        exOrderResultRepository.save(resultEntity);

        return order;
    }

    @Override
    public PagingResultVO<ExSearchVO> dispatherExOrderSearch(DispatcherSearchOrderParam param, Boolean forHistory) {

        //param.setHistoryFlg(forHistory);
        ExListParam exListParam = OrderConvertor.INSTANCE.convert2ExParam(param);
        return new PagingResultVO<>(orderMapper.searchWithConditionsAndPagingTotal(exListParam), orderMapper.searchWithConditionsAndPaging(exListParam));
    }

    /**
     * 创建快车以及站点订单
     * @param param
     * @return
     */
    @Override
    public ExpressOrderEntity createExpressStpOrder(ExpressCreateOrderParam param) {

        //1，乘客账户存在时，前端未传值的情况下，取得乘客信息放到对应参数当中
        MemberEntity member = memberService.createNewMember(param.getUserMobile());

        OrderPriceVO oprv = null;

        if (param.getIdServiceType() == Constants.ServiceType.EXPRESS) {
            //定价ID未知时，取得并保存
            ExpressPriceParam stpParam = new ExpressPriceParam();
            stpParam.setRegionCode(param.getRegionCode());
            stpParam.setInStation(param.getInStation());
            StringBuilder origins = new StringBuilder(param.getStartAddressLatitude()).append(",").append(param.getStartAddressLongitude());
            StringBuilder destinations = new StringBuilder(param.getEndAddressLatitude()).append(",").append(param.getEndAddressLongitude());
            stpParam.setOrigins(origins.toString());
            stpParam.setDestinations(destinations.toString());
            stpParam.setCarpoolType(param.getCarpoolType());
            stpParam.setIdStation(param.getIdStation());

            oprv = this.getExpressStpPrice(stpParam);
        } else {
            //TODO 城乡出行价格计算取得
            ContrySidePriceParam csSideParam = new ContrySidePriceParam();
            csSideParam.setRegionCode(param.getRegionCode());
            csSideParam.setInStation(param.getInStation());
            StringBuilder origins = new StringBuilder(param.getStartAddressLatitude()).append(",").append(param.getStartAddressLongitude());
            StringBuilder destinations = new StringBuilder(param.getEndAddressLatitude()).append(",").append(param.getEndAddressLongitude());
            csSideParam.setOrigins(origins.toString());
            csSideParam.setDestinations(destinations.toString());
            csSideParam.setCarpoolType(param.getCarpoolType());
            csSideParam.setIdStation(param.getIdStation());

            oprv = this.getContrysidePrice(csSideParam);
        }

        //创建订单
        ExpressOrderEntity order = new ExpressOrderEntity();
        if (StringUtil.empty2Null(param.getIdOrder())==null) {
            order.setIdOrder(StringUtil.createOrderID(9, param.getIdServiceType()));
            order.setIdTask(param.getIdTask());
            order.setIdFranchisee(param.getIdFranchisee());
            order.setRegionCode(param.getRegionCode());
            order.setOrderType(Constants.ExpressServiceType.STP_EXPRESS);
            order.setStatus(Constants.OrderStatus.ORDER_STATUS_CREATED);
            int paymentStatus = (param.getPaymentStatus() == null) ? Constants.PaymentStatus.UN_PAY : param.getPaymentStatus();
            order.setPaymentStatus(paymentStatus);
            int paymentRequitment = (param.getPaymentRequitment() == null) ? Constants.PaymentRequitment.IN_ADVANCE : param.getPaymentRequitment();
            order.setPaymentRequitment(paymentRequitment);
            order.setDivideAccountsStatus(Constants.DivideAccountsStatus.UN);
            order.setCreateBy("capacity");
        } else {
            order = orderRepository.findByIdOrder(param.getIdOrder());
            //entity.setIdOrder(param.getIdOrder());
            order.setUpdateBy("capacity");
        }
        order.setIdMember(member.getIdMember());

        order.setIdServicePriceType(oprv.getIdServicePriceType());
        order.setIdServiceType(param.getIdServiceType());
        order.setIdVehicleType(param.getIdVehicleType());


        order.setPriceRule(param.getPriceRule());

        order.setCarpoolType(param.getCarpoolType());//拼车包车用这个
        order.setCarpoolService(param.getCarpoolService());
        order.setIdStation(param.getIdStation());
        order.setInStation(param.getInStation());
        order.setUserName(param.getUserName());
        order.setUserMobile(param.getUserMobile());
        order.setPassengerName(param.getUserName());//传值下单用户名
        order.setPassengerMobile(param.getPassengerMobile());
        order.setPassengerNumber(param.getPassengerNumber());
        order.setAppointmentTime(DateUtil.parseLocalDateTime(param.getAppointmentTime()));
        order.setAssignTime(DateUtil.parseLocalDateTime(param.getAssignTime()));
        order.setDriverLongitude(param.getDriverLongitude());
        order.setDeptime(DateUtil.parseLocalDateTime(param.getDeptime()));
        order.setStartAddress(param.getStartAddress());
        order.setStartAddressLongitude(param.getStartAddressLongitude());
        order.setStartAddressLatitude(param.getStartAddressLatitude());
        order.setEndAddress(param.getEndAddress());
        order.setEndAddressLongitude(param.getEndAddressLongitude());
        order.setEndAddressLatitude(param.getEndAddressLatitude());
        order.setDesttime(DateUtil.parseLocalDateTime(param.getDesttime()));
        order.setDropOffArea(param.getDropOffArea());
        order.setDropOffAreaLongitude(param.getDropOffAreaLongitude());
        order.setDropOffAreaLatitude(param.getDropOffAreaLatitude());
        order.setOrderSource(param.getOrderSource());

        order.setReferenceDistance(oprv.getOrderDistance());
        order.setEstimatedTime(oprv.getSpendTime());
        float money = oprv.getTotalPrice();
        if (param.getCarpoolType() == 0)
            money = money * param.getPassengerNumber();
        order.setEstimatedMoney(money);
        order.setOrderMemo(param.getOrderMemo());

        order = (ExpressOrderEntity) orderRepository.save(order);

        //追加订单状态
        ExpressOrderStatusHistoryEntity orderStatus = new ExpressOrderStatusHistoryEntity();
        orderStatus.setIdOrder(order.getIdOrder());
        orderStatus.setStatus(order.getStatus());
        orderStatus.setCreateBy("capacity");
        orderStatus.setMemo("运力商系统录入订单");
        orderStatusHistoryRepository.save(orderStatus);

        //订单结果(未完成)
        ExpressOrderResultEntity resultEntity = exOrderResultRepository.findByIdOrder(order.getIdOrder());
        if (resultEntity == null)
            resultEntity = OrderConvertor.INSTANCE.exOrderReslutConvert(param);

        resultEntity.setIdOrder(order.getIdOrder());
        resultEntity.setOrderDistance(oprv.getOrderDistance());
        resultEntity.setOrderReferenceDistance(oprv.getOrderDistance());
        resultEntity.setOrderSpendTime(oprv.getSpendTime());
        resultEntity.setIdServicePriceSetting(oprv.getIdServicePriceType());
        resultEntity.setOrderBasePrice(oprv.getBasePrice());
        resultEntity.setOrderPerKilometres(oprv.getPerKilometres());
        resultEntity.setOrderPerTime(oprv.getPerTime());
        resultEntity.setOverMileMoney(oprv.getOverMileMoney());
        resultEntity.setOverTimeMoney(oprv.getOverTimeMoney());
        resultEntity.setBaseTotalMoney(oprv.getTotalPrice());
        exOrderResultRepository.save(resultEntity);

        return order;
    }

    /**
     * 更新快车以及站点订单
     * @param param
     * @return
     */
    @Override
    public ExpressOrderEntity updateExpressStpOrder(ExpressCreateOrderParam param) {

        //1，乘客账户存在时，前端未传值的情况下，取得乘客信息放到对应参数当中
        MemberEntity member = memberService.createNewMember(param.getUserMobile());

        //定价ID未知时，取得并保存
        ExpressPriceParam stpParam = new ExpressPriceParam();
        stpParam.setRegionCode(param.getRegionCode());
        stpParam.setInStation(param.getInStation());
        StringBuilder origins = new StringBuilder(param.getStartAddressLatitude()).append(",").append(param.getStartAddressLongitude());
        StringBuilder destinations = new StringBuilder(param.getEndAddressLatitude()).append(",").append(param.getEndAddressLongitude());
        stpParam.setOrigins(origins.toString());
        stpParam.setDestinations(destinations.toString());
        stpParam.setCarpoolType(param.getCarpoolType());
        stpParam.setIdStation(param.getIdStation());

        OrderPriceVO oprv = this.getExpressStpPrice(stpParam);

        //创建订单
        ExpressOrderEntity entity = new ExpressOrderEntity();

        entity.setIdOrder(param.getIdOrder());
        entity.setIdMember(member.getIdMember());
        entity.setIdFranchisee(param.getIdFranchisee());
        entity.setIdServicePriceType(oprv.getIdServicePriceType());
        entity.setIdServiceType(param.getIdServiceType());
        entity.setIdVehicleType(param.getIdVehicleType());
        entity.setIdTask(param.getIdTask());
        entity.setRegionCode(param.getRegionCode());
        entity.setPriceRule(param.getPriceRule());
        entity.setOrderType(Constants.ExpressServiceType.STP_EXPRESS);
        entity.setCarpoolType(param.getCarpoolType());//拼车包车用这个
        entity.setCarpoolService(param.getCarpoolService());
        entity.setIdStation(param.getIdStation());
        entity.setInStation(param.getInStation());
        entity.setUserName(param.getUserName());
        entity.setUserMobile(param.getUserMobile());
        entity.setPassengerName(param.getUserName());//传值下单用户名
        entity.setPassengerMobile(param.getPassengerMobile());
        entity.setPassengerNumber(param.getPassengerNumber());
        entity.setAppointmentTime(DateUtil.parseLocalDateTime(param.getAppointmentTime()));
        entity.setAssignTime(DateUtil.parseLocalDateTime(param.getAssignTime()));
        entity.setDriverLongitude(param.getDriverLongitude());
        entity.setDeptime(DateUtil.parseLocalDateTime(param.getDeptime()));
        entity.setStartAddress(param.getStartAddress());
        entity.setStartAddressLongitude(param.getStartAddressLongitude());
        entity.setStartAddressLatitude(param.getStartAddressLatitude());
        entity.setEndAddress(param.getEndAddress());
        entity.setEndAddressLongitude(param.getEndAddressLongitude());
        entity.setEndAddressLatitude(param.getEndAddressLatitude());
        entity.setDesttime(DateUtil.parseLocalDateTime(param.getDesttime()));
        entity.setDropOffArea(param.getDropOffArea());
        entity.setDropOffAreaLongitude(param.getDropOffAreaLongitude());
        entity.setDropOffAreaLatitude(param.getDropOffAreaLatitude());
        entity.setOrderSource(param.getOrderSource());
        int status = Constants.OrderStatus.ORDER_STATUS_CREATED;
        if (param.getStatus() != null)
            status = param.getStatus();
        entity.setStatus(status);
        int paymentStatus = (param.getPaymentStatus() == null) ? Constants.PaymentStatus.UN_PAY : param.getPaymentStatus();
        entity.setPaymentStatus(paymentStatus);
        int paymentRequitment = (param.getPaymentRequitment() == null) ? Constants.PaymentRequitment.IN_ADVANCE : param.getPaymentRequitment();
        entity.setPaymentRequitment(paymentRequitment);
        entity.setDivideAccountsStatus(Constants.DivideAccountsStatus.UN);
        entity.setReferenceDistance(oprv.getOrderDistance());
        entity.setEstimatedTime(oprv.getSpendTime());
        float money = oprv.getTotalPrice();
        if (param.getCarpoolType() == 0)
            money = money * param.getPassengerNumber();
        entity.setEstimatedMoney(money);
        entity.setOrderMemo(param.getOrderMemo());
        entity.setUpdateBy(Constants.Def_CreateBy);
        entity = (ExpressOrderEntity) orderRepository.save(entity);

        //订单结果(未完成)
        ExpressOrderResultEntity resultEntity = exOrderResultRepository.findByIdOrder(entity.getIdOrder());
        if (resultEntity == null)
            resultEntity = OrderConvertor.INSTANCE.exOrderReslutConvert(param);

        resultEntity.setIdOrder(entity.getIdOrder());
        resultEntity.setOrderDistance(oprv.getOrderDistance());
        resultEntity.setOrderReferenceDistance(oprv.getOrderDistance());
        resultEntity.setOrderSpendTime(oprv.getSpendTime());
        resultEntity.setIdServicePriceSetting(oprv.getIdServicePriceType());
        resultEntity.setOrderBasePrice(oprv.getBasePrice());
        resultEntity.setOrderPerKilometres(oprv.getPerKilometres());
        resultEntity.setOrderPerTime(oprv.getPerTime());
        resultEntity.setOverMileMoney(oprv.getOverMileMoney());
        resultEntity.setOverTimeMoney(oprv.getOverTimeMoney());
        resultEntity.setBaseTotalMoney(oprv.getTotalPrice());
        exOrderResultRepository.save(resultEntity);

        return entity;
    }

    /**
     * 快车价格更改
     * @param param
     * @return
     */
    @Override
    public Boolean reCalculatePrice(ExpressRePriceParam param) {
        boolean result = orderRepository.updatePrice(param.getOrderPrice(), param.getIdOrder()) == 0;
        if (result){
            // TODO 价格更改记录

        }
        return result;
    }

    /**
     * 快车司机改派
     * @param param
     * @return
     */
    @Transactional
    @Override
    public Boolean reDispatchDriver(DispatchDriverParam param) {
        // 检查订单状态
        ExpressOrderEntity order = orderRepository.findByIdOrder(param.getIdOrder());
        if (order == null)
            throw new BusinessException(5002, "订单不存在，请检查参数idOrder是否正确");

        if (order.getStatus() > Constants.OrderStatus.ORDER_STATUS_GOTO_RESERVATION)
            throw new BusinessException(5002, "订单已经在执行，不能转派，如需改派请去服务订单列表强制改派");

        if (StringUtil.isBlank(param.getIdDriver()))
            throw new BusinessException(5002, "指定司机ID不能为空");

        DriverInfoVO driver = driverService.driverInfo(param.getIdDriver());
        if (driver == null)
            throw new BusinessException(5002, "司机不存在，请检查参数idDriver是否正确");

        // 司机账户冻结不能派单
        if (driver.getStatus() == Constants.DriverStatus.FREEZE)
            throw new BusinessException(5002,"司机账户被冻结,不能派单");

        if (!vehicleService.verifyVehicleType(driver.getIdVehicleType(), order.getIdVehicleType()))
            throw new BusinessException(5002, "车辆类型不匹配，无法派单！");

        int orderType = Constants.OrderType.APPOINTMENT;
        Duration dur = Duration.between(LocalDateTime.now(),order.getAppointmentTime());
        long minute = dur.toMinutes();
        //20分钟以前
        if(minute<=20) {
            orderType = Constants.OrderType.REALTIME;
        }

        // 实时单
        if (Constants.OrderType.REALTIME == order.getOrderType() && driver.getStatus() != Constants.DriverStatus.ONLINE)
            throw new BusinessException(5002,"实时单只能指派空闲司机");

        String driverName = StringUtil.isBlank(driver.getNickName()) ? driver.getRealName() : driver.getNickName();
        String driverInfo = driverName + "/" + driver.getDriverMobile();

        int orderSource = order.getOrderSource();
        //接受同程的订单
        if (Constants.OrderSource.TONGCHENG_RIDE == orderSource) {
            //ElongOrderParam elongParam = ThirdPartyOrderConvertor.INSTANCE.Convert2ElongParam(param);
            //this.tryAccept(param);

            OrderStatusDTO dto = new OrderStatusDTO()
                        .setStatus(TongChengConstants.ELong_OrderType.get(Constants.OrderStatus.ORDER_STATUS_ACCEPTED))
                        .setDriverName(driverName)
                        .setDriverPhone(driver.getDriverMobile())
                        .setVehiclePlateNum(driver.getPlateNumber())
                        .setVehicleColor(driver.getColor())
                        .setVehicleModel(driver.getModel())
                        .setVehicleBrand(driver.getBrand());

            dto.setOrderId(order.getExternalOrderId());
            dto.setSupplierOrderId(order.getIdOrder());

            String idChannel = authService.findIdChannel(null, order.getIdFranchisee());
            if (StringUtil.isBlank(idChannel))
                throw new BusinessException(5002, "未找到对应的同程渠道，请检查渠道ID");

            log.info("reDispatchDriver OrderStatusDTO:"+ JSON.toJSONString(dto));
            log.info("reDispatchDriver driverInfo:"+ JSON.toJSONString(driver));
            cacheRedis.writeOrderDriverValue(order.getIdOrder(), JSON.toJSONString(driver));

            log.info("reDispatchDriver driverInfo cacheRedis:"+ cacheRedis.getOrderDriverValue(order.getIdOrder()));

            ResultVO resultVO = callback.orderStatus(idChannel, dto);
            if (resultVO.getStatus() != 200)
                throw new BusinessException(5002, "同程接口回调失败，请重新执行");
        }

        //更新订单司机
        boolean result = orderRepository.updateDriver(param.getIdDriver(),
                driver.getIdFleet(),
                driverInfo,
                Constants.OrderStatus.ORDER_STATUS_ACCEPTED,
                driver.getPlateNumber(),
                driver.getVehicleName(),
                LocalDateTime.now(),
                param.getIdOrder()) == 1;
        if (result){
            exDispatchRepository.save(new ExpressOrderDispatchEntity(param));
        }

        // 3.更新订单系统派单时间
        //orderRepository.updateAssignTime(param.getIdOrder(), LocalDateTime.now());

//        // 4.更新订单用车类型（0：实时 1：预约）
//        orderRepository.updateOrderType(param.getIdOrder(), orderType);

        // 实时单
        if (Constants.OrderType.REALTIME == orderType) {
            //更新司机状态
            result = driverRepository.driverUpdateStatus(Constants.DriverStatus.TAKE_ORDER, param.getIdDriver()) == 1;
            if (!result){
                return false;
            }
            //更新司机上线任务状态
            result = driverRepository.driverUpdateOperationStatus(Constants.DriverOperationStatus.EXPRESS_ONLINE, param.getIdDriver()) == 1;
            if (result){
                exDispatchRepository.save(new ExpressOrderDispatchEntity(param));
            }
        }

        // TODO 订单操作记录
        ExpressOrderOperationHistory oph = new ExpressOrderOperationHistory();
        oph.setIdOrder(param.getIdOrder());
        oph.setIdFranchisee(order.getIdFranchisee());
        oph.setCreateBy(param.getDispatcher());
        oph.setOperation(String.format(MessageTemplate.ExOrderOperation.DISPATCH_ORDER,
                param.getDispatcher(),
                param.getIdOrder(),
                driver.getRealName()));
        oph.setOperationFlag(0);
        exOrderOperationHistoryRepository.save(oph);

        //追加订单状态
        ExpressOrderStatusHistoryEntity orderStatus = new ExpressOrderStatusHistoryEntity();
        orderStatus.setIdOrder(param.getIdOrder());
        orderStatus.setStatus(Constants.OrderStatus.ORDER_STATUS_ACCEPTED);
        orderStatus.setCreateBy(Constants.Def_CreateBy);
        orderStatus.setMemo(oph.getOperation());
        orderStatusHistoryRepository.save(orderStatus);

        return result;
    }

    /**
     * 快车司机派单
     * @param param
     * @return
     */
    @Transactional
    @Override
    public Boolean dispatchDriver(DispatchDriverParam param) {
        boolean result = false;
        ExpressOrderEntity order = orderRepository.findByIdOrder(param.getIdOrder());
        if (order == null)
            throw new BusinessException(5002, "订单不存在，请检查参数idOrder是否正确");

        if (order.getStatus() >= Constants.OrderStatus.ORDER_STATUS_CANCEL)
            throw new BusinessException(5002, "订单已取消，无法派单");

        DriverInfoVO driver = driverService.driverInfo(param.getIdDriver());
        if (driver == null)
            throw new BusinessException(5002, "司机不存在，请检查参数idDriver是否正确");

        //VehicleTypeEntity vt = vehicleTypeRepository.findByIdDriver(param.getIdDriver());
        Integer carpoolType = order.getCarpoolType();
        if (Constants.OrderCarpoolType.Chartered == carpoolType){
            //司机和车辆信息
            if (!vehicleService.verifyVehicleType(driver.getIdVehicleType(), order.getIdVehicleType()))
                throw new BusinessException(5002, "车辆类型不匹配，无法派单！");
        }

        int orderType = Constants.OrderType.APPOINTMENT;
        Duration dur = Duration.between(LocalDateTime.now(),order.getAppointmentTime());
        long minute = dur.toMinutes();
        //20分钟以前
        if(minute<=20){
            orderType = Constants.OrderType.REALTIME;
        }

        // 实时单
        if (Constants.OrderType.REALTIME == orderType) {
            //派订单给任务
            OrderParam orderParam = new OrderParam();
            orderParam.setIdDriver(param.getIdDriver());
            orderParam.setModuleType(StringUtil.orderType(param.getIdOrder()));
            JobPlatformEntity task = jobPlatformBiz.assignOrderToJob(order, orderParam);

            // 1.更新订单状态任务ID
            orderRepository.updateIdTask(param.getIdOrder(),task.getIdTask(),param.getDispatcher());
        }

//        DriverEntity driver = driverRepository.findByIdDriver(param.getIdDriver());
//        if (driver == null)
//            throw new BusinessException(5002, "司机不存在，请检查参数idDriver是否正确");

//        DriverProfileEntity driverProfile = driverProfileRepository.findByIdDriverProfile(driver.getIdDriverProfile());
        String driverName = StringUtil.isNotBlank(driver.getNickName()) ? driver.getNickName() : driver.getRealName();
        String driverInfo = driverName + "/" + driver.getDriverMobile();

//        //司机车辆信息取得
//        VehicleEntity dv = vehicleRepository.findByIdDriver(param.getIdDriver());
//        ExpressOrderEntity entity = orderRepository.findByIdOrder(param.getIdOrder());
        if (StringUtil.isBlank(order.getIdDriver()) || !order.getIdDriver().equals(param.getIdDriver())) {
            int orderSource = order.getOrderSource();
            //接受同程的订单
            if (Constants.OrderSource.TONGCHENG_RIDE == orderSource) {
                //ElongOrderParam elongParam = ThirdPartyOrderConvertor.INSTANCE.Convert2ElongParam(param);
                //this.tryAccept(param);

                OrderStatusDTO dto = new OrderStatusDTO()
                        .setStatus(TongChengConstants.ELong_OrderType.get(Constants.OrderStatus.ORDER_STATUS_ACCEPTED))
                        .setDriverName(driverName)
                        .setDriverPhone(driver.getDriverMobile())
                        .setVehiclePlateNum(driver.getPlateNumber())
                        .setVehicleColor(driver.getColor())
                        .setVehicleModel(driver.getModel())
                        .setVehicleBrand(driver.getBrand());

                dto.setOrderId(order.getExternalOrderId());
                dto.setSupplierOrderId(order.getIdOrder());

                String idChannel = authService.findIdChannel(null, order.getIdFranchisee());
                if (StringUtil.isBlank(idChannel))
                    throw new BusinessException(5002, "未找到对应的同程渠道，请检查渠道ID");

                log.info("reDispatchDriver OrderStatusDTO:" + JSON.toJSONString(dto));

                ResultVO resultVO = callback.orderStatus(idChannel, dto);
                if (resultVO.getStatus() != 200)
                    throw new BusinessException(5002, "同程接口回调失败，请重新执行");
            }
        }

        // 2.更新订单司机信息
        result = orderRepository.updateDriver(param.getIdDriver(),
                driver.getIdFleet(),
                driverInfo,
                Constants.OrderStatus.ORDER_STATUS_ACCEPTED,
                driver.getPlateNumber(),
                driver.getVehicleName(),
                LocalDateTime.now(),
                param.getIdOrder()) == 1;
        if (!result){
            return false;
        }

        // 3.更新订单系统派单时间
        //orderRepository.updateAssignTime(param.getIdOrder(), LocalDateTime.now());

//        // 4.更新订单用车类型（0：实时 1：预约）
//        orderRepository.updateOrderType(param.getIdOrder(), orderType);

        // 实时单
        if (Constants.OrderType.REALTIME == orderType) {
            //更新司机状态
            result = driverRepository.driverUpdateStatus(Constants.DriverStatus.TAKE_ORDER, param.getIdDriver()) == 1;
            if (!result){
                return false;
            }
            //更新司机上线任务状态
            result = driverRepository.driverUpdateOperationStatus(Constants.DriverOperationStatus.EXPRESS_ONLINE, param.getIdDriver()) == 1;
            if (result){
                exDispatchRepository.save(new ExpressOrderDispatchEntity(param));
            }
        }

        // TODO 订单操作记录
        ExpressOrderOperationHistory oph = new ExpressOrderOperationHistory();
        oph.setIdOrder(param.getIdOrder());
        oph.setIdFranchisee(order.getIdFranchisee());
        oph.setCreateBy(param.getDispatcher());
        oph.setOperation(String.format(MessageTemplate.ExOrderOperation.DISPATCH_ORDER,
                param.getDispatcher(),
                param.getIdOrder(),
                driver.getRealName()));
        oph.setOperationFlag(0);
        exOrderOperationHistoryRepository.save(oph);

        //追加订单状态
        ExpressOrderStatusHistoryEntity orderStatus = new ExpressOrderStatusHistoryEntity();
        orderStatus.setIdOrder(param.getIdOrder());
        orderStatus.setStatus(Constants.OrderStatus.ORDER_STATUS_ACCEPTED);
        orderStatus.setCreateBy(Constants.Def_CreateBy);
        orderStatus.setMemo(oph.getOperation());
        orderStatusHistoryRepository.save(orderStatus);

        return true;
    }

    /**
     * 取消快车司机派单
     * @param param
     * @return
     */
    @Transactional
    @Override
    public Boolean unDispatchDriver(DispatchDriverParam param) {

        boolean result = false;

        List<String> listIdOrder = StringUtil.StringToList(param.getIdOrder());
        for (String idOrder:listIdOrder) {
            DispatchDriverParam orderParam = new DispatchDriverParam();
            orderParam.setIdOrder(idOrder);
            orderParam.setIdDriver(param.getIdDriver());
            orderParam.setDispatcher(param.getDispatcher());
            unDispatchDriverByOrderId(orderParam);
        }

        return true;
    }

    private void unDispatchDriverByOrderId(DispatchDriverParam param) {

        ExpressOrderEntity order = orderRepository.findByIdOrder(param.getIdOrder());
        if (order==null){
            throw new BusinessException(4001,"订单不存在");
        }
        if(!order.getIdDriver().equals(param.getIdDriver()))
            throw new BusinessException(4001,"订单不属于当前司机");

        // 1.更新订单状态任务ID
        orderRepository.updateIdTask(param.getIdOrder(),null,param.getDispatcher());

        // 2.更新订单司机信息
        orderRepository.updateDriver(null,null, null, Constants.OrderStatus.ORDER_STATUS_CREATED,
                null,null, null, param.getIdOrder());

        // 3.更新订单系统派单时间
        //orderRepository.updateAssignTime(param.getIdOrder(), null);

        // 更新订单状态 Todo 需要？
        driverRepository.driverUpdateStatus(Constants.DriverStatus.ONLINE, param.getIdDriver());
        driverRepository.driverUpdateOperationStatus(Constants.DriverOperationStatus.EXPRESS_ONLINE, param.getIdDriver());
        exDispatchRepository.save(new ExpressOrderDispatchEntity(param));

        // TODO 订单操作记录
        ExpressOrderOperationHistory oph = new ExpressOrderOperationHistory();
        oph.setIdOrder(param.getIdOrder());
        oph.setIdFranchisee(order.getIdFranchisee());
        oph.setCreateBy(param.getDispatcher());
        oph.setOperation(String.format(MessageTemplate.ExOrderOperation.CANCEL_ORDER,
                param.getDispatcher(),
                param.getIdOrder()));
        oph.setOperationFlag(0);
        exOrderOperationHistoryRepository.save(oph);

        //追加订单状态
        ExpressOrderStatusHistoryEntity orderStatus = new ExpressOrderStatusHistoryEntity();
        orderStatus.setIdOrder(param.getIdOrder());
        orderStatus.setStatus(Constants.OrderStatus.ORDER_STATUS_CREATED);
        orderStatus.setCreateBy(Constants.Def_CreateBy);
        orderStatus.setMemo(oph.getOperation());
        orderStatusHistoryRepository.save(orderStatus);

        // 任务ID不为空
        if (StringUtil.isNotBlank(order.getIdTask())){
            //实时订单
            JobPlatformEntity task = jobRepository.findByIdTask(order.getIdTask());
            if (task==null){
                throw new BusinessException(4001,"任务异常");
            }
            // 在乘人数(已在车上人数+将要乘车人数，以下车人数不在内）+ 当前派单的订单人数
            Integer passengers_incar_number = task.getPassengersIncarNumber() - order.getPassengerNumber();
            // 预估金额
            Float taskSumMoney = NumUtil.getFloat(task.getTaskSumMoney()) - NumUtil.getFloat(order.getEstimatedMoney());
            // 任务额外金额
            Float taskAdditionalMoney = NumUtil.getFloat(task.getTaskAdditionalMoney()) - NumUtil.getFloat(order.getAdditionalMoney());
            // 任务优惠金额
            Float task_coupon_money = NumUtil.getFloat(task.getTaskCouponMoney()) - NumUtil.getFloat(order.getCouponDiscount());
            //更新任务信息(派单完成)
            //task.setStatus(Constants.TaskStatus.DISPATCH_COMPLETE);
            task.setPassengersIncarNumber(passengers_incar_number);
            task.setTaskSumMoney(taskSumMoney);
            task.setTaskAdditionalMoney(taskAdditionalMoney);
            task.setTaskCouponMoney(task_coupon_money);
            task.setUpdateBy(param.getDispatcher());
            jobRepository.saveAndFlush(task);
            //jobRepository.save(new JobPlatformEntity(task));
        }

    }

    /**
     * 快车订单取消
     * @param idOrder
     * @return
     */
    @Override
    public Boolean cancelOrder(String idOrder,String operator) {

        // 检查订单状态
        ExpressOrderEntity order = orderRepository.findById(idOrder).orElse(null);
        if (order == null)
            throw new BusinessException(5002, "订单不存在，请检查参数idOrder是否正确");

        if (order.getStatus() > Constants.OrderStatus.ORDER_STATUS_ARRIVED)
            throw new BusinessException(5002, "订单已开始服务，无法删除。");

        if (order.getOrderSource() == Constants.OrderSource.TONGCHENG_RIDE) {
            if (StringUtil.isNotBlank(order.getIdDriver())) {
                DriverInfoVO vo = driverService.driverInfo(order.getIdDriver());

                //同程路径：/elong/order/driver/cancel
                OrderStatusDTO dto = (OrderStatusDTO) new OrderStatusDTO()
                .setStatus(TongChengConstants.ELong_OrderType.get(Constants.OrderStatus.ORDER_STATUS_ADMIN_CANCELED))
                .setDriverName(vo.getRealName())
                .setDriverPhone(vo.getDriverMobile())
                .setVehiclePlateNum(vo.getPlateNumber())
                .setVehicleColor(vo.getColor())
                .setVehicleModel(vo.getModel())
                .setVehicleBrand(vo.getBrand())
                .setCancelType(TongChengConstants.CancelType.CUSTOMER_SERVICE)
                .setCancelReason("因故障无法派单");

                dto.setOrderId(order.getExternalOrderId());
                dto.setSupplierOrderId(order.getIdOrder());

                String idChannel = authService.findIdChannel(null, order.getIdFranchisee());
                if (StringUtil.isBlank(idChannel))
                    throw new BusinessException(5002, "未找到对应的同程渠道，请检查渠道ID");

                ResultVO resultVO = callback.orderStatus(idChannel, dto);
                if (resultVO != null)
                    log.info("ResultVO:" + JSON.toJSONString(resultVO));

                if (resultVO.getStatus() != 200)
                    throw new BusinessException(5002, "同程取消失败"+resultVO.getMessage());
            }
        }

        boolean result = orderRepository.updateOrderStatus(idOrder,
                Constants.OrderStatus.ORDER_STATUS_ADMIN_CANCELED, operator) == 1;
        if (result){
            //订单取消历史
            ExOrderCancelHistoryEntity exCancel = new ExOrderCancelHistoryEntity();
            exCancel.setIdOrder(idOrder);
            exCancel.setOperationType(Constants.OrderOperatorType.ALLIANCE);
            exCancel.setIdOperation("");
            String reason = String.format("同程订单号：%s%s", idOrder, "无法处理");
            exCancel.setReason(reason);
            //todo 取消原因编码
            exCancel.setReasonCode(Constants.OrderCancelType.OTHER_REASON);
            exCancel.setMemo(String.format(MessageTemplate.OrderStatus.SYSTEM_CANCEL, idOrder));
            orderCancelHistoryRepository.save(exCancel);
            log.debug("订单取消历史执行成功");

            //添加订单状态变化历史
            ExpressOrderStatusHistoryEntity exStatus = new ExpressOrderStatusHistoryEntity();
            exStatus.setIdOrder(idOrder);
            exStatus.setStatus(Constants.OrderStatus.ORDER_STATUS_ADMIN_CANCELED);
            exStatus.setCreateBy(Constants.Def_CreateBy_ELong);
            exStatus.setMemo(String.format(MessageTemplate.OrderStatus.SYSTEM_CANCEL, idOrder));
            orderStatusHistoryRepository.save(exStatus);
            log.debug("订单取消状态变化历史执行成功");

//            // TODO 订单操作履历
//            ExpressOrderOperationHistory oph = new ExpressOrderOperationHistory();
//            oph.setIdOrder(idOrder);
//            oph.setIdFranchisee("");
//            oph.setCreateBy(operator);
//            oph.setOperation(String.format(MessageTemplate.ExOrderOperation.CANCEL_ORDER, operator,idOrder));
//            oph.setOperationFlag(0);
//            oph.setIdOperation("1");
//            exOrderOperationHistoryRepository.save(oph);
        }
        return result;
    }

    @Override
    public OrderVO virtualAcceptOrder(String idOrder, String idDriver) {
        ExpressOrderEntity order = orderRepository.findByIdOrder(idOrder);
        if (order == null)
            throw new BusinessException(5002, "订单不存在，请检查参数idOrder是否正确");

        if (order.getStatus() > Constants.OrderStatus.ORDER_STATUS_ACCEPTED)
            throw new BusinessException(5002,"订单已开始服务，无法虚拟接单。");

        if (order.getStatus() == Constants.OrderStatus.ORDER_STATUS_ACCEPTED &&
                StringUtil.isNotBlank(order.getIdDriver())) {
            if (order.getVirtualOrderAccepted() == 1) {
                return OrderConvertor.INSTANCE.exOrderToView(order);
            } else {
                throw new BusinessException(5002, "订单已安排司机，如需更换司机请执行改派才做。");
            }
        }

        if (StringUtil.isBlank(idDriver)) {
            idDriver = TongChengConstants.ELong_VirtualDriver.get(order.getIdFranchisee());
            if (StringUtil.isBlank(idDriver) && StringUtil.isNotBlank(order.getIdFranchisee())) {
                DriverEntity entity = driverService.findDriverByIdFranchiseeWithRand(order.getIdFranchisee());
                if (entity == null)
                    throw new BusinessException(5002, "未找到该加盟商有注册完整司机");
                else
                    idDriver = entity.getIdDriver();
            }
        }

        DriverInfoVO driverInfoVO = driverService.driverInfo(idDriver);

        String driverName = StringUtil.isNotBlank(driverInfoVO.getNickName()) ? driverInfoVO.getNickName() : driverInfoVO.getRealName();
        //String driverInfo = driverName + "/" + driverInfoVO.getDriverMobile();

        //接受同程的订单 司机派单或者改派
        if (Constants.OrderSource.TONGCHENG_RIDE == order.getOrderSource()) {
            OrderStatusDTO dto = new OrderStatusDTO()
                    .setStatus(TongChengConstants.ELong_OrderType.get(Constants.OrderStatus.ORDER_STATUS_ACCEPTED))
                    .setDriverName(driverName)
                    .setDriverPhone(driverInfoVO.getDriverMobile())
                    .setVehiclePlateNum(driverInfoVO.getPlateNumber())
                    .setVehicleColor(driverInfoVO.getColor())
                    .setVehicleModel(driverInfoVO.getModel())
                    .setVehicleBrand(driverInfoVO.getBrand());

            dto.setOrderId(order.getExternalOrderId());
            dto.setSupplierOrderId(order.getIdOrder());

            String idChannel = authService.findIdChannel(null, order.getIdFranchisee());
            if (StringUtil.isBlank(idChannel))
                throw new BusinessException(5002, "未找到对应的同程渠道，请检查渠道ID");
            cacheRedis.writeOrderDriverValue(idOrder, JSON.toJSONString(driverInfoVO));

            ResultVO resultVO = callback.orderStatus(idChannel, dto);
            if (resultVO.getStatus() != 200) {
                cacheRedis.clearOrderDriverValue(idOrder);
                throw new BusinessException(5002, "同程接口回调失败，请重新执行");
            }
        }

        //缓存保存
        order.setIdOrder(idOrder);
        order.setIdDriver(idDriver);
        order.setStatus(Constants.OrderStatus.ORDER_STATUS_ACCEPTED);
        order.setVirtualOrderAccepted(1);
        order.setDriverInfo(driverName);
        OrderVO vo = OrderConvertor.INSTANCE.exOrderToView(orderRepository.saveAndFlush(order));

        //vo有值后，清空缓存

        return vo;
    }

    @Override
    public OrderVO virtualAcceptOrder(DispatchParam param) {
        if (StringUtil.isBlank(param.getIdOrder()))
            throw new BusinessException(4001, "订单号idOrder不能为空");

        String idDriver;
        if (StringUtil.isNotBlank(param.getIdDriver())) {
            idDriver = param.getIdDriver();
        } else {
            idDriver = TongChengConstants.ELong_VirtualDriver.get(param.getIdFranchisee());
            if (StringUtil.isBlank(idDriver) && StringUtil.isNotBlank(param.getIdFranchisee())) {
                DriverEntity entity = driverService.findDriverByIdFranchiseeWithRand(param.getIdFranchisee());
                if (entity == null)
                    throw new BusinessException(5002, "未找到该加盟商有注册完整司机");
                else
                    idDriver = entity.getIdDriver();
            }
        }

        return this.virtualAcceptOrder(param.getIdOrder(), idDriver);
    }

    /**
     * 快车订单检索查询
     * @param param
     * @return
     */
    @Override
    public PagingResultVO<ExSearchVO> exOrderSearch(ExListParam param,Boolean forHistory) {
        //param.setHistoryFlg(forHistory);
        return new PagingResultVO<>(orderMapper.searchWithConditionsAndPagingTotal(param), orderMapper.searchWithConditionsAndPaging(param));
    }

    /**
     * 订单详情
     * @param idOrder
     * @return
     */
    @Override
    public ExDetailVO exOrderDetail(String idOrder,Boolean forHistory) {
        List<ExDetailVO.StatusHistory> statusHistories = orderMapper.getExOrderDetailHistory(idOrder);
        List<ExDetailVO.StatusHistory> statusHistoriesR = new ArrayList<>();
        ExDetailVO.Base base = null;
        if (forHistory){
            base = orderMapper.getExOrderDetailBaseForHistory(idOrder);
        }else{
            base = orderMapper.getExOrderDetailBase(idOrder);
        }
        if (base==null)throw new BusinessException(5002,"订单号不存在请检查");
        ArrayList<String> child;
        ExpressOrderEntity orderEntity = null;
        if (forHistory){
            orderEntity = OrderConvertor.INSTANCE.convertToHistory(orderHistoryRepository.findById(idOrder).orElse(null));
        }else{
            orderEntity = orderRepository.findById(idOrder).orElse(null);
        }
        ExOrderCancelHistoryEntity och = orderCancelHistoryRepository.findById(idOrder).orElse(null);
        for (ExDetailVO.StatusHistory v:statusHistories) {
            child = new ArrayList<>();
            switch (v.getStatus()){
                case 0://乘客发单
                    v.setTitle("乘客发单");
                    child.add(StrUtil.join(":","发单时间",v.getCreateTime()));
                    child.add(StrUtil.join(":","预估里程/时长",StrUtil.builder().append(orderEntity.getReferenceDistance()).append("公里/").append(orderEntity.getEstimatedTime()).append("分钟")));
                    child.add(StrUtil.join(":","预估价格","￥"+orderEntity.getEstimatedMoney()));
                    statusHistoriesR.add(v);
                    break;
//                case 1://平台派单
//                    v.setTitle("平台派单");
//                    child.add(StrUtil.join(":","车牌号",StrUtil.builder().append(orderEntity.getPlateNumber())));
//                    child.add(StrUtil.join(":","车辆",StrUtil.builder().append(orderEntity.getModel())));
//                    child.add(StrUtil.join(":","预估接驾",StrUtil.builder().append("待定")));
//                    statusHistoriesR.add(v);
//                    break;
                case 2://司机接单
                    if (orderEntity.getIdDriver()!=null){
                        v.setTitle("司机接单");
                        VehicleEntity dv = vehicleRepository.findByIdDriver(orderEntity.getIdDriver());
                        child.add(StrUtil.join(":","接单时间",v.getCreateTime()));
                        child.add(StrUtil.join(":","车牌号",StrUtil.builder().append(dv.getPlateNumber())));
                        //child.add(StrUtil.join(":","车辆",StrUtil.builder().append(orderEntity.getModel())));
                        child.add(StrUtil.join(":","预估接驾里程/时长",StrUtil.builder().append("待定")));
                        statusHistoriesR.add(v);
                    }

                    break;
                case 4://司机到达上车点
                    v.setTitle("司机到达上车点");
                    child.add(StrUtil.join(":","到达上车地点时间",v.getCreateTime()));
                    child.add(StrUtil.join(":","真实接驾里程/时长",StrUtil.builder().append("待定")));
                    statusHistoriesR.add(v);
                    break;
                case 5://乘客上车
                    v.setTitle("乘客上车");
                    child.add(StrUtil.join(":","上车时间",v.getCreateTime()));
                    statusHistoriesR.add(v);
                    break;
                case 6://到达目的地
                    v.setTitle("到达目的地");
                    child.add(StrUtil.join(":","到达时间",v.getCreateTime()));
                    child.add(StrUtil.join(":","实际里程",orderEntity.getOrderDistance()));
                    statusHistoriesR.add(v);
                    break;
                case 7://未支付
                    v.setTitle("订单待支付");
                    child.add(StrUtil.join(":","支付状态",StrUtil.builder().append("未支付")));
                    child.add(StrUtil.join(":","支付时间",v.getCreateTime()));
                    child.add(StrUtil.join(":","乘客应付",orderEntity.getPayMoney()));
                    child.add(StrUtil.join(":","司机应收",orderEntity.getOrderMoney()));
                    statusHistoriesR.add(v);
                    break;
                case 8://已支付
                    v.setTitle("订单支付");
                    child.add(StrUtil.join(":","支付状态",StrUtil.builder().append("已支付")));
                    child.add(StrUtil.join(":","支付时间",v.getCreateTime()));
                    child.add(StrUtil.join(":","乘客应付",orderEntity.getPayMoney()));
                    child.add(StrUtil.join(":","司机应收",orderEntity.getOrderMoney()));
                    statusHistoriesR.add(v);
                    break;
                case 11://乘客下单后取消订单 用户取消、取消原因、操作时间
                    v.setTitle("已取消");
                    child.add("用户取消");
                    if(och!=null){
                        child.add(StrUtil.join(":","取消原因",och.getReason()));
                        child.add(StrUtil.join(":","操作时间",och.getCreateTime()));
                    }
                    statusHistoriesR.add(v);
                    break;
//                case 12://司机已拒绝
//                    v.setTitle("司机已拒绝");
//                    child.add(StrUtil.join(":","真实接驾",StrUtil.builder().append("待定")));
//                    statusHistoriesR.add(v);
//                    break;
                case 13://系统已销单
                    v.setTitle("已销单");
                    child.add("系统自动取消");
                    if(och!=null){
                        child.add(StrUtil.join(":","取消原因",och.getReason()));
                        child.add(StrUtil.join(":","操作时间",och.getCreateTime()));
                    }
                    statusHistoriesR.add(v);
                    break;
                case 14://司机已取消
                    v.setTitle("已取消");
                    child.add("司机取消");
                    if(och!=null){
                        child.add(StrUtil.join(":","取消原因",och.getReason()));
                        child.add(StrUtil.join(":","操作时间",och.getCreateTime()));
                    }
                    statusHistoriesR.add(v);
                    break;
                case 15://客服已取消
                    v.setTitle("已取消");
                    child.add("客服取消");
                    if(och!=null){
                        child.add(StrUtil.join(":","取消原因",och.getReason()));
                        child.add(StrUtil.join(":","操作时间",och.getCreateTime()));
                    }
                    statusHistoriesR.add(v);
                    break;
            }
            v.setChild(child);
        }
        return new ExDetailVO(base, statusHistoriesR,null);
    }

    @Override
    public Boolean exOrderDestroy(ExOrderDestroyParam param) {
        ExpressOrderEntity expressOrderEntity;
        try {
            expressOrderEntity = orderRepository.findById(param.getIdOrder()).get();
            if (expressOrderEntity.getStatus()==Constants.OrderStatus.ORDER_STATUS_ADMIN_CANCELED)
                throw new BusinessException(5002,"该订单已被销单,无法重复销单");
        }catch (NoSuchElementException e){
            throw new BusinessException(5002,"订单ID[idOrder]不存在,请检查");
        }
        expressOrderEntity.setStatus(Constants.OrderStatus.ORDER_STATUS_ADMIN_CANCELED);
        orderRepository.save(expressOrderEntity);
        return destroyRepository.save(ExpressConvertor.INSTANCE.convert(param))!=null;
    }

    @Override
    public Boolean exReMemo(String idOrder, String memo) {
        return orderMapper.updateMemo(idOrder,memo);
    }

    /**
     * 快车价格分段计算方法
     * @param param
     * @return
     */
    private OrderPriceVO moneyCalculate(PriceParam param) {
        float money = 0.00f;

        float base_price = 0.00f;
        float other_price = 0.00f;
        float per_kilometres = 0.00f;
        float per_time = 0.00f;

        OrderPriceVO opv = null;
        ExpressCommonPriceEntity cep = null;
        try {
            if (StringUtil.isNotBlank(param.getIdFranchisee())) {
                cep = expressCommonPriceRepository.findByRegionCodeAndIdFranchisee(param.getRegionCode(), param.getIdFranchisee());
            }

            if (cep == null) {
                List<ExpressCommonPriceEntity> lst = expressCommonPriceRepository.findByRegionCode(param.getRegionCode());
                cep = lst.get(0);
            }
        } catch (Exception e) {
            throw new BusinessException(5002,"未找到该地区的定价记录");
        }

        if (cep != null) {
            // 普通服务起步价
            money = cep.getServicePrice();
            base_price = cep.getServicePrice();
            per_kilometres = cep.getExceedingMileagePrice();

            // 分段距离
            float od0 = 0;
            float od1 = 0;
            float od2 = 0;
            float od3 = 0;

            // 分段价格
            float ltp0 = 0;
            float ltp1 = 0;
            float ltp2 = 0;
            float ltp3 = 0;

            // 分段费用
            float dx0 = 0;
            float dx1 = 0;
            float dx2 = 0;
            float dx3 = 0;

            // 分段距离计算公式
            if (cep.getSecondServiceMileage() > cep.getMaxServiceMileage()) {
                if (cep.getThirdServiceMileage() > cep.getSecondServiceMileage()) {
                    if (cep.getFourthServiceMileage() > cep.getThirdServiceMileage()) {
                        // 第三段距离里程计算
                        od3 = param.getOrderDistance() - cep.getFourthServiceMileage();
                        od3 = (od3 > 0) ? od3 : 0;

                        // 第三段收费计算
                        ltp3 = cep.getFourthMileagePrice();
                        dx3 = ltp3 * od3;
                    }

                    // 第二段距离里程计算
                    od2 = param.getOrderDistance() - cep.getThirdServiceMileage() - od3;
                    od2 = (od2 > 0) ? od2 : 0;

                    // 第二段收费计算
                    ltp2 = cep.getSecondMileagePrice();
                    dx2 = ltp2 * od2;
                }

                // 第一段距离里程计算
                od1 = param.getOrderDistance() - cep.getThirdServiceMileage() - od2 - od3;
                od1 = (od1 > 0) ? od1 : 0;

                // 第一段收费计算
                ltp1 = cep.getSecondMileagePrice();
                dx1 = ltp1 * od1;
            }

            // 第零段距离里程计算
            if (param.getOrderDistance() > cep.getMaxServiceMileage()) {
                od0 = (param.getOrderDistance() < cep.getSecondServiceMileage()) ? (param.getOrderDistance() - cep.getMaxServiceMileage()) : (cep.getSecondServiceMileage() - cep.getMaxServiceMileage());
                od0 = (od0 > 0) ? od0 : 0;
            }
            // 第零段收费计算
            ltp0 = cep.getExceedingMileagePrice();
            dx0 = ltp0 * od0;

            // 里程计费
            money = money + dx0 + dx1 + dx2 + dx3;

            int overtime = param.getSpendTime() - cep.getMaxServiceTime();
            per_time = cep.getExceedingTimePrice();
            if (overtime > 0) {
                money = money + overtime * cep.getExceedingTimePrice();
            }

            if (param.getWaitingTime() > 10) {
                int t = (int) Math.floor(param.getWaitingTime() - 10);
                money = money + t * cep.getWaitingTimePrice();
            }

            other_price = money - base_price;

            opv = new OrderPriceVO();
            opv.setIdServicePriceType(String.valueOf(cep.getIdServicePriceType()));
            opv.setIdFranchisee(cep.getIdFranchisee());
            opv.setTotalPrice(Convert.toFloat(new BigDecimal(money).setScale(2, RoundingMode.HALF_UP).toString()));
            opv.setBasePrice(base_price);
            opv.setBasePrice(Convert.toFloat(new BigDecimal(base_price).setScale(2, RoundingMode.HALF_UP).toString()));
            opv.setOtherPrice(Convert.toFloat(new BigDecimal(other_price).setScale(2, RoundingMode.HALF_UP).toString()));
            opv.setOrderDistance(param.getOrderDistance());
            opv.setSpendTime(param.getSpendTime());
        }

        return opv;
    }

    /**
     * 站点价格按线路按人头收费计算方法
     * @param espParam
     * @return
     */
    private OrderPriceVO stpMoneyCalculate(ExpressPriceParam espParam) {
        //ParameterEntity parameter = new ParameterEntity();
        // StringBuffer cal_memo = new StringBuffer();
        float money = 0;
        float base_price = 0;
        float other_price = 0;

        List<ExpressStpPriceEntity> lst = exStpPriceRepository.findByRegionCodeAndCarpoolType(espParam.getRegionCode(), espParam.getCarpoolType());
        ExpressStpPriceEntity stp = null;

        //寻找对应站点定价，没有找到则采用当前城市定价
        if (lst != null) {
            for(int i=0; i<lst.size(); i++) {
                ExpressStpPriceEntity stpIndex = lst.get(i);
                if (espParam.getCarpoolType() == 1) {
                    if (espParam.getIdVehicleType() == stpIndex.getIdVehicleType()) {
                        if (StringUtil.isBlank(stpIndex.getIdStation())) {
                            stp = lst.get(i);
                            if (StringUtil.isBlank(espParam.getIdStation()))
                                break;
                        } else if (StringUtil.isNotBlank(espParam.getIdStation()) && espParam.getIdStation().equals(stpIndex.getIdStation())) {
                            stp = lst.get(i);
                            break;
                        }
                    }
                } else {
                    if (StringUtil.isBlank(stpIndex.getIdStation())) {
                        stp = lst.get(i);
                        if (StringUtil.isBlank(espParam.getIdStation()))
                            break;
                    } else if (StringUtil.isNotBlank(espParam.getIdStation()) && espParam.getIdStation().equals(stpIndex.getIdStation())) {
                        stp = lst.get(i);
                        break;
                    }
                }
            }
        }

        if (stp != null) {
            float od = espParam.getOrderDistance();
            //马山县超过70公里按照1元/公里计费
            //15到70公里按照0.5元每公里计费
            //15公里12元起步价
//            if (espParam.getRegionCode().equals("450124")) {
//                int distance = (int) (od + 0.5);
//                od = (float) distance;
//                if (od > 70) {
//                    money = od - 70;
//                    od = 70;
//                }
//            }

            if (od > stp.getLongDistanceKilometers()) {
                money = stp.getLongDistanceFee();
                float ltp = od - stp.getLongDistanceKilometers();
                money = money + ltp * stp.getOverMileageFee();
            } else if (od > stp.getBaseKilometers())
                money = stp.getLongDistanceFee();
            else if (od > stp.getStartingKilometers())
                money = stp.getBaseFee();
            else {
                money = stp.getStartingFee();
            }
        } else {
            return null;
        }

        base_price = money - other_price;
        OrderPriceVO opv = new OrderPriceVO();
        opv.setIdServicePriceType(stp.getIdServicePriceType());
        opv.setIdFranchisee(stp.getIdFranchisee());
        opv.setTotalPrice(Convert.toFloat(new BigDecimal(money).setScale(2, RoundingMode.HALF_UP).toString()));
        opv.setBasePrice(Convert.toFloat(new BigDecimal(base_price).setScale(2, RoundingMode.HALF_UP).toString()));
        opv.setOtherPrice(Convert.toFloat(new BigDecimal(other_price).setScale(2, RoundingMode.HALF_UP).toString()));
        opv.setOrderDistance(espParam.getOrderDistance());
        opv.setSpendTime(espParam.getSpendTime());

        opv.setIdStation(espParam.getIdStation());
        opv.setInStation(espParam.getInStation());

        log.info("STP OrderPriceVO:"+JSON.toJSONString(opv));
        return opv;
    }


    /**
     * 站点价格按线路按人头收费计算方法
     * @param espParam
     * @return
     */
    //TODO
    private OrderPriceVO csMoneyCalculate(ContrySidePriceParam espParam) {
        OrderPriceVO opv = new OrderPriceVO();
        return opv;
    }

    /**
     * 获取当前司机未执行的订单列表
     * @param idDriver
     * @param status
     * @return
     */
    @Override
    public List<ExpressOrderEntity> findByIdDriverAndStatus(String idDriver,Integer status) {
        return orderRepository.findByIdDriverAndStatus(idDriver, status);
    }

    /**
     * 订单支付详情
     * @param idOrder
     * @return
     */
    @Override
    public ExOrderBillInfoVO getOrderBillInfo(String idOrder,Boolean forHistory) {

        ExpressOrderEntity order = null;
        if (forHistory){
            order = OrderConvertor.INSTANCE.convertToHistory(orderHistoryRepository.findById(idOrder).orElse(null));
        }else{
            order = orderRepository.findById(idOrder).orElse(null);
        }
        if (order==null)throw new BusinessException(5002,"订单号不存在请检查");

        ExpressOrderSettlementEntity es = orderSettlementRepository.findByIdOrder(idOrder);
        ExDriverAccountDetailEntity ed = accountDetailRepository.findByRelateOrderNo(idOrder);

        if (es == null)
            es = new ExpressOrderSettlementEntity();
        if (ed == null)
            ed = new ExDriverAccountDetailEntity();

        ExOrderBillInfoVO.PassengerBill pb = new ExOrderBillInfoVO.PassengerBill();
        /** 总价 */
        pb.setTotal(es.getOrderTotal());
        /** 基础费 */
        pb.setBasic(es.getOrderMoney());
        /** 时长费 */
        pb.setDuration(0F);
        /** 里程费 */
        pb.setMileage(0F);
        /** 远途费 */
        pb.setLongDistance(es.getOrderLongDistanceMoney());
        /** 节假日服务费 */
        pb.setHoliday(0F);
        /** 综合能耗费 */
        pb.setEnergy(0F);
        ExOrderBillInfoVO.PassengerPayInfo pp = new ExOrderBillInfoVO.PassengerPayInfo();
        /** 支付金额 */
        pp.setPayMoney(order.getPayMoney());
        /** 支付时间 */
        if (es.getPayTime()!=null){
            pp.setPayTime(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(es.getPayTime()));
        }
        /** 支付状态 */
        pp.setPayStatus(Constants.Payment_Status.get(order.getPaymentStatus()));
        /** 支付渠道 */
        pp.setPayChannel(Constants.Payment_Type.get(es.getPaymentType()));
        /** 发票状态 */
        pp.setInvoiceStatus("-");
        /** 退款费用 */
        pp.setRefund(0F);
        /** 高速费 */
        pp.setHighSpeed(0F);
        /** 停车费 */
        pp.setParking(0F);
        /** 路桥费 */
        pp.setBridge(es.getOrderRoadMoney());
        /** 限时折扣 */
        pp.setDiscount(0F);
        /** 其他费 */
        pp.setOther(es.getOrderOther());
        /** 节假日服务费 */
        pp.setHoliday(0F);
        /** 综合能耗费 */
        pp.setEnergy(0F);

        ExOrderBillInfoVO.DriverBill db = new ExOrderBillInfoVO.DriverBill();
        /** 总价 */
        if (ed != null){
            db.setTotal(ed.getMoney());
        }else{
            db.setTotal(0F);
        }
        /** 基础费 */
        db.setBasic(0F);
        /** 时长费 */
        db.setDuration(0F);
        /** 里程费 */
        db.setMileage(0F);
        /** 高速费 */
        db.setHighSpeed(0F);
        /** 停车费 */
        db.setParking(0F);
        /** 路桥费 */
        db.setBridge(0F);
        /** 远途费 */
        db.setLongDistance(0F);
        /** 其他费 */
        db.setOther(0F);
        /** 免佣补贴金额 */
        db.setAllowance(0F);
        /** 节假日服务费 */
        db.setHoliday(0F);
        /** 信息服务费 */
        db.setInformation(0F);
        /** 综合能耗费 */
        db.setEnergy(0F);

        return new ExOrderBillInfoVO(pb, pp,db);
    }

    @Override
    public PagingResultVO<ExOrderSettlementViewVO> exOrderBillViewLst(ExSettlementViewListParam param) {
        Page<ExOrderSettlementViewVO> page = exOrderSettlementRepository.findByIdFranchisee(param.getIdFranchisee(), PageRequest.of(param.getPageIndex() - 1, param.getPageSize()));
        return new PagingResultVO<>(page.getTotalElements(),page.getContent());
    }

    @Override
    public ExOrderInfoVO orderInfo(String idOrder) {
        ExpressOrderEntity entity = orderRepository.findById(idOrder).get();
        if (entity == null)
            throw new BusinessException(5002,"订单号不存在请检查");
        return ExpressConvertor.INSTANCE.convert(entity);
    }

    /**
     * 获取站点以及快车价格
     * @param param
     * @return
     */
    @Override
    public OrderPriceVO getExpressPrice(PriceParam param) {
        log.debug("getExpressPrice 计算价格");

        RouteVO routeVO = routeRedis.calOrderDistance(
                param.getCoordinateType()
                , param.getOrigins(), param.getDestinations());

        if (routeVO == null)
            return null;

        param.setOrderDistance(routeVO.getDistance());
        param.setSpendTime(routeVO.getSpendTime());

        return exCalculate(param);
    }

    /**
     * 快车价格分段计算方法
     * @param param
     * @return
     */
    private OrderPriceVO exCalculate(PriceParam param) {
        float money = 0.00f;

        float base_price = 0.00f;
        float other_price = 0.00f;
        float per_kilometres = 0.00f;
        float per_time = 0.00f;

        OrderPriceVO opv = null;
        ExpressCommonPriceEntity cep = null;
        try {
            if (StringUtil.isNotBlank(param.getIdFranchisee())) {
                cep = expressCommonPriceRepository.findByRegionCodeAndIdFranchisee(param.getRegionCode(), param.getIdFranchisee());
            }

            if (cep == null) {
                List<ExpressCommonPriceEntity> lst = expressCommonPriceRepository.findByRegionCode(param.getRegionCode());
                cep = lst.get(0);
            }
        } catch (Exception e) {
            throw new BusinessException(5002,"未找到该地区的定价记录");
        }

        if (cep != null) {
            // 普通服务起步价
            money = cep.getServicePrice();
            base_price = cep.getServicePrice();
            per_kilometres = cep.getExceedingMileagePrice();

            // 分段距离
            float od0 = 0;
            float od1 = 0;
            float od2 = 0;
            float od3 = 0;

            // 分段价格
            float ltp0 = 0;
            float ltp1 = 0;
            float ltp2 = 0;
            float ltp3 = 0;

            // 分段费用
            float dx0 = 0;
            float dx1 = 0;
            float dx2 = 0;
            float dx3 = 0;

            // 分段距离计算公式
            if (cep.getSecondServiceMileage() > cep.getMaxServiceMileage()) {
                if (cep.getThirdServiceMileage() > cep.getSecondServiceMileage()) {
                    if (cep.getFourthServiceMileage() > cep.getThirdServiceMileage()) {
                        // 第三段距离里程计算
                        od3 = param.getOrderDistance() - cep.getFourthServiceMileage();
                        od3 = (od3 > 0) ? od3 : 0;

                        // 第三段收费计算
                        ltp3 = cep.getFourthMileagePrice();
                        dx3 = ltp3 * od3;
                    }

                    // 第二段距离里程计算
                    od2 = param.getOrderDistance() - cep.getThirdServiceMileage() - od3;
                    od2 = (od2 > 0) ? od2 : 0;

                    // 第二段收费计算
                    ltp2 = cep.getSecondMileagePrice();
                    dx2 = ltp2 * od2;
                }

                // 第一段距离里程计算
                od1 = param.getOrderDistance() - cep.getThirdServiceMileage() - od2 - od3;
                od1 = (od1 > 0) ? od1 : 0;

                // 第一段收费计算
                ltp1 = cep.getSecondMileagePrice();
                dx1 = ltp1 * od1;
            }

            // 第零段距离里程计算
            if (param.getOrderDistance() > cep.getMaxServiceMileage()) {
                od0 = (param.getOrderDistance() < cep.getSecondServiceMileage()) ? (param.getOrderDistance() - cep.getMaxServiceMileage()) : (cep.getSecondServiceMileage() - cep.getMaxServiceMileage());
                od0 = (od0 > 0) ? od0 : 0;
            }
            // 第零段收费计算
            ltp0 = cep.getExceedingMileagePrice();
            dx0 = ltp0 * od0;

            // 里程计费
            money = money + dx0 + dx1 + dx2 + dx3;

            int overtime = param.getSpendTime() - cep.getMaxServiceTime();
            per_time = cep.getExceedingTimePrice();
            if (overtime > 0) {
                money = money + overtime * cep.getExceedingTimePrice();
            }

            if (param.getWaitingTime() > 10) {
                int t = (int) Math.floor(param.getWaitingTime() - 10);
                money = money + t * cep.getWaitingTimePrice();
            }

            other_price = money - base_price;

            opv = new OrderPriceVO();
            opv.setIdServicePriceType(String.valueOf(cep.getIdServicePriceType()));
            opv.setIdFranchisee(cep.getIdFranchisee());
            opv.setTotalPrice(Convert.toFloat(new BigDecimal(money).setScale(2, RoundingMode.HALF_UP).toString()));
            opv.setBasePrice(base_price);
            opv.setBasePrice(Convert.toFloat(new BigDecimal(base_price).setScale(2, RoundingMode.HALF_UP).toString()));
            opv.setOtherPrice(Convert.toFloat(new BigDecimal(other_price).setScale(2, RoundingMode.HALF_UP).toString()));
            opv.setOrderDistance(param.getOrderDistance());
            opv.setSpendTime(param.getSpendTime());
        }

        return opv;
    }

}
